package com.lwl.concurrency.collection;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * SimpleDateFormat 是线程不安全的,不能作为成员对象使用
 * 有如下几种方法使用:
 * 1 在方法内部创建 SimpleDateFormat 对象,作为局部变量使用,但是每次都创建对象也是占用内存资源的
 * 2 使用SimpleDateFormat的parse()方法前后加锁,但是获取锁的过程也是一个性能损耗,不利于多线程环境并行
 * 3 使用ThreadLocal为每一条线程生成一个SimpleDateFormat对象,这个适用于线程池工作,因为线程池种的线程
 * 不会使用完立即销毁,很可能会继续执行其他任务,这样避免了每次调用方法都去创建SimpleDateFormat对象,
 * 一条线程对应一个SimpleDateFormat对象,保证了多线程安全,节省系统资源.
 * 如果是每次调用方法都重新创建一个线程,和在方法种创建局部变量基本一样
 *
 *
 * @author liwenlong - 2018/4/1 19:35
 */
public class ThreadLocalTest {

    //使用ThreadLocal为每一条线程都产生一个SimpleDateFormat
    private static final ThreadLocal<SimpleDateFormat> local = new ThreadLocal<>();

    public static class ParseDate implements Runnable {
        int i = 0;

        public ParseDate(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            try {
                SimpleDateFormat sdf = local.get();
                if (sdf == null){
                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    local.set(sdf);
                }
                Date date = sdf.parse("2018-04-01 20:53:" + (i % 60));
                System.out.println(i + ":" + date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            executorService.execute(new ParseDate(i));
        }
        executorService.shutdown();
    }

}
